﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace CommonUtils
{
    [AttributeUsage(AttributeTargets.Class)]
    public class AutoTaskAttribute : Attribute
    {
        /// <summary>
        /// 入口程序
        /// </summary>
        public string EnterMethod { get; set; }
        /// <summary>
        /// 执行间隔秒数（未设置或0 则只执行一次）
        /// </summary>
        public int IntervalSeconds { get; set; } = 0;
        /// <summary>
        /// 首次启动延时时间
        /// 当StartTime 为空时有效
        /// </summary>
        public int DueSeconds { get; set; } = 0;
        public string StartTime { get; set; }

        //保留对Timer 的引用，避免回收
        public static List<System.Threading.Timer> timers = new List<System.Threading.Timer>();
        public static void RegisterTask(Assembly assembly)
        {
            new Task(() => StartAutoTask(assembly)).Start();
        }
        /// <summary>
        /// 启动定时任务
        /// </summary>
        private static void StartAutoTask(Assembly assembly)
        {
            var types = assembly.ExportedTypes.Where(t => Attribute.IsDefined(t, typeof(AutoTaskAttribute))).ToList();
            foreach (var t in types)
            {
                try
                {
                    var att = (AutoTaskAttribute)Attribute.GetCustomAttribute(t, typeof(AutoTaskAttribute));
                    if (att != null)
                    {
                        if (string.IsNullOrWhiteSpace(att.EnterMethod))
                        {
                            throw new Exception("未指定任务入口！EnterMethod");
                        }
                        var ins = Activator.CreateInstance(t);
                        var method = t.GetMethod(att.EnterMethod);

                        if (att.IntervalSeconds > 0)
                        {
                            int duetime = 0; //计算延时时间

                            if (string.IsNullOrWhiteSpace(att.StartTime))
                            {
                                if (att.DueSeconds > 0)
                                {
                                    duetime = att.DueSeconds * 1000;
                                }
                                else
                                {
                                    //默认10秒
                                    duetime = 10000;
                                }
                            }
                            else
                            {
                                var datetime = DateTime.Parse(att.StartTime);
                                var now = DateTime.Now;
                                if (DateTime.Now <= datetime)
                                {
                                    duetime = (int)(datetime - DateTime.Now).TotalSeconds * 1000;
                                }
                                else
                                {
                                    int n = (int)Math.Floor((now - datetime).TotalSeconds / att.IntervalSeconds) + 1;
                                    long aa = att.IntervalSeconds * n;
                                    duetime = (int)(datetime.AddSeconds(aa) - now).TotalMilliseconds;
                                }
                            }

                            timers.Add(new System.Threading.Timer((o) =>
                            {
                                method.Invoke(ins, null);
                            }, ins, duetime, att.IntervalSeconds * 1000));
                        }
                        else
                        {
                            method.Invoke(ins, null);
                        }
                    }

                }
                catch (Exception ex)
                {
                    LogHelper.Error(t.FullName + " 任务启动失败", ex);
                }
            }
        }

    }
}
